use std::sync::{
    Arc, RwLock,
    atomic::{AtomicUsize, Ordering},
};

use axum::{Extension, Json, http::StatusCode};
use serde::{Deserialize, Serialize};

use crate::token::Claim;

// Note: 使用static修饰
static NEXT_ID: AtomicUsize = AtomicUsize::new(1);

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct User {
    #[serde(skip_deserializing)]
    pub id: u64,
    pub name: String,
    pub age: u8,
}

#[derive(Debug, Clone, Default)]
pub struct UserStore {
    items: Arc<RwLock<Vec<User>>>,
}

// 直接使用TypedHeader<UserAgent>进行模式匹配的话, 则必须要求有对应header
// user_agent: Option<TypedHeader<UserAgent>>,
#[axum::debug_handler]
pub async fn create_user(
    _claims: Claim<String>, // 需要传入token
    Extension(store): Extension<UserStore>,
    Json(mut user): Json<User>,
) -> StatusCode {
    return match store.items.write() {
        Ok(mut guard) => {
            let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
            user.id = id as u64;
            tracing::info!("create user: {:?}", user);
            guard.push(user);
            StatusCode::CREATED
        }
        Err(e) => {
            tracing::error!("write lock failed: {}", e);
            StatusCode::INTERNAL_SERVER_ERROR
        }
    };
}

#[axum::debug_handler]
pub async fn get_user(Extension(store): Extension<UserStore>) -> Json<Vec<User>> {
    let result = match store.items.read() {
        Ok(guard) => guard.to_vec(),
        Err(e) => {
            tracing::warn!("get user failed: {}", e);
            Vec::<User>::new()
        }
    };
    Json(result)
}
